package edu.northwestern.cbits.purple_robot_manager.probes.builtin;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Looper;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.v4.content.ContextCompat;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import edu.northwestern.cbits.purple_robot_manager.R;
import edu.northwestern.cbits.purple_robot_manager.activities.settings.FlexibleListPreference;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityCheck;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityManager;
import edu.northwestern.cbits.purple_robot_manager.probes.Probe;
public class TelephonyProbe extends Probe
{
private static final String NETWORK_TYPE = "NETWORK_TYPE";
private static final String CALL_STATE = "CALL_STATE";
private static final String HAS_ICC_CARD = "HAS_ICC_CARD";
private static final String NETWORK_COUNTRY_ISO = "NETWORK_COUNTRY_ISO";
private static final String NETWORK_OPERATOR = "NETWORK_OPERATOR";
private static final String SIM_COUNTRY_ISO = "SIM_COUNTRY_ISO";
private static final String SIM_OPERATOR_NAME = "SIM_OPERATOR_NAME";
private static final String NETWORK_OPERATOR_NAME = "SIM_OPERATOR_NAME";
private static final String SIM_OPERATOR = "SIM_OPERATOR_NAME";
private static final String PHONE_TYPE = "PHONE_TYPE";
private static final String SIM_STATE = "SIM_STATE";
private static final String DEVICE_SOFTWARE_VERSION = "DEVICE_SOFTWARE_VERSION";
private static final String CDMA_STATION = "CDMA_STATION";
private static final String CDMA_LONGITUDE = "CDMA_LONGITUDE";
private static final String CDMA_SYSTEM_ID = "CDMA_SYSTEM_ID";
private static final String CDMA_LATITUDE = "CDMA_LATITUDE";
private static final String CDMA_NETWORK_ID = "CDMA_NETWORK_ID";
private static final String GSM_ERROR_RATE = "GSM_ERROR_RATE";
private static final String GSM_SIGNAL_STRENGTH = "GSM_SIGNAL_STRENGTH";
private static final String CDMA_ECIO = "CDMA_ECIO";
private static final String CDMA_EVDO_ECIO = "CDMA_EVDO_ECIO";
private static final String CDMA_EVDO_DBM = "CDMA_EVDO_DBM";
private static final String CDMA_DBM = "CDMA_DBM";
private static final String CDMA_EVDO_SNR = "CDMA_EVDO_SNR";
private static final String IS_FORWARDING = "IS_FORWARDING";
private static final String SERVICE_STATE = "SERVICE_STATE";
private static final boolean DEFAULT_ENABLED = true;
private static final String ENABLED = "config_probe_telephony_enabled";
private static final String FREQUENCY = "config_probe_telephony_frequency";
private long _lastCheck = 0;
private long _lastSignalCheck = 0;
private boolean _isForwarding = false;
private int _cdmaDbm = 0;
private int _cdmaEcio = 0;
private int _evdoDbm = 0;
private int _evdoEcio = 0;
private int _evdoSnr = 0;
private int _gsmErrorRate = 0;
private int _gsmSignalStrength = 0;
private int _serviceState = 0;
private PhoneStateListener _listener = null;
@Override
public String getPreferenceKey() {
return "built_in_telephony";
}
@Override
public String name(Context context)
{
return "edu.northwestern.cbits.purple_robot_manager.probes.builtin.TelephonyProbe";
}
@Override
public String title(Context context)
{
return context.getString(R.string.title_telephony_probe);
}
@Override
public String probeCategory(Context context)
{
return context.getResources().getString(R.string.probe_device_info_category);
}
@Override
public void enable(Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putBoolean(TelephonyProbe.ENABLED, true);
e.commit();
}
@Override
public void disable(Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putBoolean(TelephonyProbe.ENABLED, false);
e.commit();
}
@Override
@SuppressWarnings("deprecation")
public boolean isEnabled(final Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final TelephonyProbe me = this;
if (super.isEnabled(context))
{
if (this._listener == null)
{
Looper looper = Looper.myLooper();
if (looper == null)
Looper.prepare();
this._listener = new PhoneStateListener()
{
@Override
public void onCallForwardingIndicatorChanged(boolean forwarding)
{
if (me._isForwarding != forwarding)
{
me._isForwarding = forwarding;
me._lastCheck = 0;
}
}
@Override
public void onSignalStrengthsChanged(SignalStrength signal)
{
long now = System.currentTimeMillis();
if (now - me._lastSignalCheck > 5000)
{
me._cdmaDbm = signal.getCdmaDbm();
me._cdmaEcio = signal.getCdmaEcio();
me._evdoDbm = signal.getEvdoDbm();
me._evdoEcio = signal.getEvdoEcio();
me._evdoSnr = signal.getEvdoSnr();
me._gsmErrorRate = signal.getGsmBitErrorRate();
me._gsmSignalStrength = signal.getGsmSignalStrength();
me._lastCheck = 0;
me._lastSignalCheck = now;
}
}
@Override
public void onServiceStateChanged(ServiceState serviceState)
{
if (me._serviceState != serviceState.getState())
{
me._serviceState = serviceState.getState();
me._lastCheck = 0;
}
}
};
}
long now = System.currentTimeMillis();
if (prefs.getBoolean(TelephonyProbe.ENABLED, TelephonyProbe.DEFAULT_ENABLED))
{
if (ContextCompat.checkSelfPermission(context, "android.permission.READ_PHONE_STATE") == PackageManager.PERMISSION_GRANTED) {
synchronized (this) {
manager.listen(this._listener, PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | PhoneStateListener.LISTEN_SERVICE_STATE | PhoneStateListener.LISTEN_SIGNAL_STRENGTH);
long freq = Long.parseLong(prefs.getString(TelephonyProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY));
if (now - this._lastCheck > freq) {
try {
Bundle bundle = new Bundle();
bundle.putString("PROBE", this.name(context));
bundle.putLong("TIMESTAMP", System.currentTimeMillis() / 1000);
String operatorName = manager.getSimOperatorName();
if (operatorName == null || operatorName.trim().length() == 0)
operatorName = context.getString(R.string.label_no_operator);
bundle.putInt(TelephonyProbe.CALL_STATE, manager.getCallState());
bundle.putString(TelephonyProbe.NETWORK_COUNTRY_ISO, manager.getNetworkCountryIso());
bundle.putString(TelephonyProbe.NETWORK_OPERATOR, manager.getNetworkOperator());
bundle.putString(TelephonyProbe.NETWORK_OPERATOR_NAME, manager.getNetworkOperatorName());
bundle.putString(TelephonyProbe.SIM_COUNTRY_ISO, manager.getSimCountryIso());
bundle.putString(TelephonyProbe.SIM_OPERATOR, manager.getSimOperator());
bundle.putString(TelephonyProbe.SIM_OPERATOR_NAME, operatorName);
bundle.putBoolean(TelephonyProbe.HAS_ICC_CARD, manager.hasIccCard());
bundle.putString(TelephonyProbe.NETWORK_TYPE, this.networkType(manager.getNetworkType()));
bundle.putString(TelephonyProbe.PHONE_TYPE, this.phoneType(manager.getPhoneType()));
bundle.putString(TelephonyProbe.SIM_STATE, this.simState(manager.getSimState()));
bundle.putString(TelephonyProbe.DEVICE_SOFTWARE_VERSION, manager.getDeviceSoftwareVersion());
bundle.putBoolean(TelephonyProbe.IS_FORWARDING, this._isForwarding);
if (this._serviceState == ServiceState.STATE_EMERGENCY_ONLY)
bundle.putString(TelephonyProbe.SERVICE_STATE, context.getString(R.string.service_state_emergency));
else if (this._serviceState == ServiceState.STATE_IN_SERVICE)
bundle.putString(TelephonyProbe.SERVICE_STATE, context.getString(R.string.service_state_in_service));
if (this._serviceState == ServiceState.STATE_OUT_OF_SERVICE)
bundle.putString(TelephonyProbe.SERVICE_STATE, context.getString(R.string.service_state_out_service));
if (this._serviceState == ServiceState.STATE_POWER_OFF)
bundle.putString(TelephonyProbe.SERVICE_STATE, context.getString(R.string.service_state_off));
CellLocation location = manager.getCellLocation();
if (location instanceof GsmCellLocation) {
GsmCellLocation gsmLocation = (GsmCellLocation) location;
gsmLocation.fillInNotifierBundle(bundle);
bundle.putString(TelephonyProbe.NETWORK_TYPE, "GSM");
bundle.putInt(TelephonyProbe.GSM_ERROR_RATE, this._gsmErrorRate);
bundle.putInt(TelephonyProbe.GSM_SIGNAL_STRENGTH, this._gsmSignalStrength);
} else if (location instanceof CdmaCellLocation) {
CdmaCellLocation cdmaLocation = (CdmaCellLocation) location;
cdmaLocation.fillInNotifierBundle(bundle);
bundle.putString(TelephonyProbe.NETWORK_TYPE, "CDMA");
bundle.putInt(TelephonyProbe.CDMA_STATION, cdmaLocation.getBaseStationId());
bundle.putInt(TelephonyProbe.CDMA_LATITUDE, cdmaLocation.getBaseStationLatitude());
bundle.putInt(TelephonyProbe.CDMA_LONGITUDE, cdmaLocation.getBaseStationLongitude());
bundle.putInt(TelephonyProbe.CDMA_NETWORK_ID, cdmaLocation.getNetworkId());
bundle.putInt(TelephonyProbe.CDMA_SYSTEM_ID, cdmaLocation.getSystemId());
bundle.putInt(TelephonyProbe.CDMA_DBM, this._cdmaDbm);
bundle.putInt(TelephonyProbe.CDMA_ECIO, this._cdmaEcio);
bundle.putInt(TelephonyProbe.CDMA_EVDO_DBM, this._evdoDbm);
bundle.putInt(TelephonyProbe.CDMA_EVDO_ECIO, this._evdoEcio);
bundle.putInt(TelephonyProbe.CDMA_EVDO_SNR, this._evdoSnr);
} else
bundle.putString(TelephonyProbe.NETWORK_TYPE, "None");
this.transmitData(context, bundle);
} catch (SecurityException e) {
LogManager.getInstance(context).logException(e);
}
this._lastCheck = now;
}
}
}
else
SanityManager.getInstance(context).addPermissionAlert(this.name(context), "android.permission.READ_PHONE_STATE", context.getString(R.string.rationale_telephony_probe), null);
return true;
}
}
else
{
if (this._listener != null)
manager.listen(this._listener, 0);
}
return false;
}
@Override
public Bundle formattedBundle(Context context, Bundle bundle)
{
Bundle formatted = super.formattedBundle(context, bundle);
formatted.putString(context.getString(R.string.display_telephony_operator_title), bundle.getString(TelephonyProbe.NETWORK_OPERATOR_NAME));
formatted.putString(context.getString(R.string.display_telephony_network_title), bundle.getString(TelephonyProbe.PHONE_TYPE));
return formatted;
}
@Override
public String summarizeValue(Context context, Bundle bundle)
{
String operator = bundle.getString(TelephonyProbe.SIM_OPERATOR_NAME);
String network = bundle.getString(TelephonyProbe.NETWORK_TYPE);
return String.format(context.getResources().getString(R.string.summary_telephony_probe), operator, network);
}
private String simState(int simState)
{
String type = "Unknown";
switch (simState)
{
case TelephonyManager.SIM_STATE_ABSENT:
type = "Absent";
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
type = "PIN Required";
break;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
type = "PUK Required";
break;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
type = "Network Locked";
break;
case TelephonyManager.SIM_STATE_READY:
type = "Ready";
break;
}
return type;
}
private String phoneType(int phoneType)
{
String type = "Unknown";
switch (phoneType)
{
case TelephonyManager.PHONE_TYPE_NONE:
type = "None";
break;
case TelephonyManager.PHONE_TYPE_GSM:
type = "GSM";
break;
case TelephonyManager.PHONE_TYPE_CDMA:
type = "CDMA";
break;
case TelephonyManager.PHONE_TYPE_SIP:
type = "SIP";
break;
}
return type;
}
private String networkType(int networkType)
{
String type = "Unknown";
switch (networkType)
{
case TelephonyManager.NETWORK_TYPE_GPRS:
type = "GPRS";
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
type = "UTMS";
break;
case TelephonyManager.NETWORK_TYPE_EDGE:
type = "EDGE";
break;
case TelephonyManager.NETWORK_TYPE_HSDPA:
type = "HSDPA";
break;
case TelephonyManager.NETWORK_TYPE_HSUPA:
type = "HSUPA";
break;
case TelephonyManager.NETWORK_TYPE_HSPA:
type = "HSPA";
break;
case TelephonyManager.NETWORK_TYPE_CDMA:
type = "CDMA";
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0:
type = "EVDOr0";
break;
case TelephonyManager.NETWORK_TYPE_EVDO_A:
type = "EVDOrA";
break;
case TelephonyManager.NETWORK_TYPE_EVDO_B:
type = "EVDOrB";
break;
case TelephonyManager.NETWORK_TYPE_1xRTT:
type = "1x RTT";
break;
case TelephonyManager.NETWORK_TYPE_IDEN:
type = "IDEN";
break;
case TelephonyManager.NETWORK_TYPE_LTE:
type = "LTE";
break;
case TelephonyManager.NETWORK_TYPE_EHRPD:
type = "EHRPD";
break;
case TelephonyManager.NETWORK_TYPE_HSPAP:
type = "HSPA+";
break;
}
return type;
}
@Override
public Map<String, Object> configuration(Context context)
{
Map<String, Object> map = super.configuration(context);
SharedPreferences prefs = Probe.getPreferences(context);
long freq = Long.parseLong(prefs.getString(TelephonyProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY));
map.put(Probe.PROBE_FREQUENCY, freq);
return map;
}
@Override
public void updateFromMap(Context context, Map<String, Object> params)
{
super.updateFromMap(context, params);
if (params.containsKey(Probe.PROBE_FREQUENCY))
{
Object frequency = params.get(Probe.PROBE_FREQUENCY);
if (frequency instanceof Double)
{
frequency = ((Double) frequency).longValue();
}
if (frequency instanceof Long)
{
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putString(TelephonyProbe.FREQUENCY, frequency.toString());
e.commit();
}
}
}
@Override
public String summary(Context context)
{
return context.getString(R.string.summary_telephony_probe_desc);
}
@Override
@SuppressWarnings("deprecation")
public PreferenceScreen preferenceScreen(Context context, PreferenceManager manager)
{
PreferenceScreen screen = super.preferenceScreen(context, manager);
screen.setTitle(this.title(context));
screen.setSummary(R.string.summary_telephony_probe_desc);
CheckBoxPreference enabled = new CheckBoxPreference(context);
enabled.setTitle(R.string.title_enable_probe);
enabled.setKey(TelephonyProbe.ENABLED);
enabled.setDefaultValue(TelephonyProbe.DEFAULT_ENABLED);
screen.addPreference(enabled);
FlexibleListPreference duration = new FlexibleListPreference(context);
duration.setKey(TelephonyProbe.FREQUENCY);
duration.setEntryValues(R.array.probe_satellite_frequency_values);
duration.setEntries(R.array.probe_satellite_frequency_labels);
duration.setTitle(R.string.probe_frequency_label);
duration.setDefaultValue(Probe.DEFAULT_FREQUENCY);
screen.addPreference(duration);
return screen;
}
@Override
public JSONObject fetchSettings(Context context)
{
JSONObject settings = super.fetchSettings(context);
try
{
JSONObject frequency = new JSONObject();
frequency.put(Probe.PROBE_TYPE, Probe.PROBE_TYPE_LONG);
JSONArray values = new JSONArray();
String[] options = context.getResources().getStringArray(R.array.probe_satellite_frequency_values);
for (String option : options)
{
values.put(Long.parseLong(option));
}
frequency.put(Probe.PROBE_VALUES, values);
settings.put(Probe.PROBE_FREQUENCY, frequency);
}
catch (JSONException e)
{
LogManager.getInstance(context).logException(e);
}
return settings;
}
public String assetPath(Context context)
{
return "telephony-probe.html";
}
}